package start.threadlocal;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class TestThreadLocal {
    public static void main(String[] args) throws Exception {

        Thread t01 = new Thread(() -> testThreadLocal(1L));
        t01.start();
        //t01.join();
        Thread t02 = new Thread(() -> testThreadLocal(2L));
        t02.start();
        //t02.join();
        Thread t03 = new Thread(() -> testThreadLocal(3L));
        t03.start();
        //t03.join();



        //Singleton.SingletonHolder singletonHolder01 = Singleton.SingletonHolder();
        //Singleton.SingletonHolder singletonHolder02 = Singleton.SingletonHolder();
        //System.out.println(singletonHolder01);
        //System.out.println(singletonHolder02);

        //Thread t = new Thread(() -> test("abc", false));
        //t.start();
        //t.join();
        //System.out.println("--gc后--");

        //Thread t2 = new Thread(() -> test("def", false));
        //t2.start();
        //t2.join();

        //Thread t3 = new Thread(() -> test("M", false));
        //t3.start();
        //t3.join();

        //Thread t4 = new Thread(() -> test("N", false));
        //t4.start();
        //t4.join();

        //Thread t5 = new Thread(() -> test("K", false));
        //t5.start();
        //t5.join();



    }


    public static void testThreadLocal(Long s) {
        try {
            UserContext.setCurrentUserId(s);
            ThreadLocal<Long> userIdLocal = UserContext.userIdLocal;
            System.out.println(userIdLocal);
            Thread t = Thread.currentThread();
            Class<? extends  Thread> clz = t.getClass();
            Field field = clz.getDeclaredField("threadLocals");
            field.setAccessible(true);
            Object threadLocalMap = field.get(t);
            System.out.println("threadLocalMap-->" + threadLocalMap);

            Thread.sleep(5 * 1000);


        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static void test(String s, boolean isGC) {
        try {

            ThreadLocal<Object> objectThreadLocal01 = new ThreadLocal<>();
            ThreadLocal<Object> objectThreadLocal02 = new ThreadLocal<>();

            Map map = new HashMap<>();
            map.put("a", 1);
            objectThreadLocal01.set(map);

            Map map02 = new HashMap<>();
            map02.put("a", 2);
            objectThreadLocal02.set(map02);


            System.out.println(objectThreadLocal01.get());
            System.out.println(objectThreadLocal02.get());

            //ThreadLocal<Object> objectThreadLocal = new ThreadLocal<>();
            //System.out.println("当前objectThreadLocal地址"  + objectThreadLocal);
            //objectThreadLocal.set(s);
            //Object sValueB = objectThreadLocal.get();
            //System.out.println("sValueB>" + sValueB);
            if (isGC) {
                System.gc();
            }
            //Object sValueA= objectThreadLocal.get();
            //System.out.println("sValueA>" + sValueA);
            Thread t = Thread.currentThread();
            Class<? extends  Thread> clz = t.getClass();
            Field field = clz.getDeclaredField("threadLocals");
            field.setAccessible(true);
            Object threadLocalMap = field.get(t);
            System.out.println("threadLocalMap>" + threadLocalMap);
            Class<?> tlmClass = threadLocalMap.getClass();
            Field tableField = tlmClass.getDeclaredField("table");
            tableField.setAccessible(true);
            Object[] arr = (Object[]) tableField.get(threadLocalMap);
            for (Object o : arr) {
                if (o != null) {
                    Class<?> entityClass = o.getClass();
                    Field valueField = entityClass.getDeclaredField("value");
                    Field referenceField = entityClass.getSuperclass().getSuperclass().getDeclaredField("referent");
                    valueField.setAccessible(true);
                    referenceField.setAccessible(true);
                    System.out.println(String.format("弱引用key：%s, 值：%s", referenceField.get(o), valueField.get(o)));
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}


class Singleton {

    public static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();


    }

}


class NotSingleton {

    public static class NotSingletonHolder {
        private static final NotSingleton INSTANCE = new NotSingleton();
    }

}





